/**
 * Project Name:ccopsgw
 * File Name:SgipQdServer.java
 * Package Name:com.ccop.sgw.sgipqd.socket
 * Date:2016年4月1日下午6:37:15
 * Copyright (c) 2016, LiHao All Rights Reserved.
 *
*/

package com.cloud.demo.sgip;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Date;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cloud.demo.sgip.msg.SgipMsgBind;
import com.cloud.demo.sgip.msg.SgipMsgBindResp;
import com.cloud.demo.sgip.msg.SgipMsgDeliver;
import com.cloud.demo.sgip.msg.SgipMsgDeliverResp;
import com.cloud.demo.sgip.msg.SgipMsgReport;
import com.cloud.demo.sgip.msg.SgipMsgReportResp;
import com.cloud.demo.sgip.msg.SgipMsgSubmitResp;
import com.cloud.demo.sgip.msg.SgipMsgUnbind;
import com.cloud.demo.sgip.msg.SgipMsgUnbindResp;
import com.cloud.demo.utils.ByteConvert;



/**
 * ClassName:SgipQdServer <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason:	 TODO ADD REASON. <br/>
 * Date:     2016年4月1日 下午6:37:15 <br/>
 * @author   LiHao
 * @version  
 * @since    JDK 1.6
 * @see 	 
 */
public class SgipQdServer extends IoHandlerAdapter {
	private static Logger logger = LoggerFactory.getLogger(SgipQdServer.class);
	private String socketPort = "8801";
	private static SgipQdServer _instance;
	private NioSocketAcceptor acceptor=null;
	private InetSocketAddress socketAddres = null;  
	
	/**
	 * 当接口中其他方法抛出异常未被捕获时触发此方法
	 */
	public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		logger.warn("exceptionCaught:", cause.getMessage()+",clientIP:" + clientIP);
//		this.removeUserBySessionId(session);
		cause.printStackTrace();
//		session.close(true);
	}

	/**
	 * 当接收到客户端的信息
	 */
	public void messageReceived(IoSession session, Object message) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		logger.debug("服务器接收到client:{}的数据： {}", new Object[]{clientIP,message});
		byte[] inByte = (byte[]) message;
		byte [] headBytes = new byte[SgipCommand.MsgHeaderLength];
		byte totalLenBytes[]=new byte[SgipCommand.MsgTotalLength];
		byte commandIdBytes[]=new byte[SgipCommand.MsgCommandId];
		byte sequenceIdBytes[]=new byte[SgipCommand.MsgSequenceId];
		System.arraycopy(inByte, 0, headBytes, 0, SgipCommand.MsgHeaderLength);
		System.arraycopy(headBytes, 0, totalLenBytes, 0, 4);
		System.arraycopy(headBytes, 4, commandIdBytes, 0, 4);
		System.arraycopy(headBytes, 8, sequenceIdBytes, 0, 12);
		int totalLen=ByteConvert.bytesToInt(totalLenBytes);
		byte bodyBytes[]=new byte[totalLen-SgipCommand.MsgHeaderLength];
		if(bodyBytes.length>0){
		System.arraycopy(inByte, 20, bodyBytes, 0, bodyBytes.length);
		}
//		String sequenceId=ByteConvert.getStr(sequenceIdBytes);
		int commandId=ByteConvert.bytesToInt(commandIdBytes);
		switch(commandId){
			case SgipCommand.SGIP_BIND:
				logger.debug("【sgipqd】收到SMG ->Bind命令");
				SgipMsgBind msgBind=new SgipMsgBind(totalLen,commandId,sequenceIdBytes,bodyBytes);
				if(msgBind.getResult()==0){
					logger.info("【sgipqd Bind消息】,seqStr:{},loginName:{},loginPwd:{}",new Object[]{msgBind.getSeqStr(),msgBind.getLoginName(),msgBind.getLoginPassword()});
					SgipMsgBindResp bindResp=new SgipMsgBindResp();
					bindResp.setTotalLength(20+1+8);
					bindResp.setCommandId(SgipCommand.SGIP_BIND_RESP);
					bindResp.setSeqByte(sequenceIdBytes);
					bindResp.setResult((byte)0);
					this.send(session, bindResp.toByteArry());
				}else{
					logger.warn("【sgip bind 接收 解析失败】序列号：");
				}
				break;
			case SgipCommand.SGIP_UNBIND:
				logger.debug("【sgipqd】收到SMG ->UnBind命令");
				SgipMsgUnbind msgUnbind=new SgipMsgUnbind(totalLen,commandId,sequenceIdBytes);
					
				SgipMsgUnbindResp unbindResp=new SgipMsgUnbindResp();
				unbindResp.setTotalLength(20);
				unbindResp.setCommandId(SgipCommand.SGIP_UNBIND_RESP);
				unbindResp.setSeqByte(sequenceIdBytes);
				this.send(session, unbindResp.toByteArry());
				
				break;
			case SgipCommand.SGIP_DELIVER:
				logger.debug("【sgipqd】收到SMG ->Deliver命令");
				SgipMsgDeliver msgDeliver=new SgipMsgDeliver(totalLen,commandId,sequenceIdBytes,bodyBytes);
				if(msgDeliver.getResult()==0){
					logger.info("【sgipqd Deliver消息】,seqStr:{},userNum:{},spNum:{},messageCoding:{},messageLength:{},content:{}",new Object[]{msgDeliver.getSeqStr(),msgDeliver.getUserNumber(),msgDeliver.getSpNumber(),msgDeliver.getMessageCoding(),msgDeliver.getMessageLength(),msgDeliver.getMessageContent()});
					SgipMsgDeliverResp deliverResp=new SgipMsgDeliverResp();
					deliverResp.setTotalLength(20+1+8);
					deliverResp.setCommandId(SgipCommand.SGIP_DELIVER_RESP);
					deliverResp.setSeqByte(sequenceIdBytes);
					deliverResp.setResult((byte)0);
					this.send(session, deliverResp.toByteArry());
					
				}else{
					logger.warn("【sgipqd deliver 接收 解析失败】");
				}
				break;
			case SgipCommand.SGIP_REPORT:
				logger.debug("【sgipqd】收到SMG ->Report命令");
				SgipMsgReport msgReport=new SgipMsgReport(totalLen, commandId, sequenceIdBytes, bodyBytes);
				if(msgReport.getResult()==0){
					logger.info("【sgipqd Report 消息】,seqStr:{},submitSequenceNumber:{},reportType:{},userNumber:{},state:{},errorCode:{}",new Object[]{msgReport.getSeqStr(),msgReport.getSubmitSequenceNumber(),msgReport.getReportType(),msgReport.getUserNumber(),msgReport.getState(),msgReport.getErrorCode()});
					SgipMsgReportResp resportResp=new SgipMsgReportResp();
					resportResp.setTotalLength(20+1+8);
					resportResp.setCommandId(SgipCommand.SGIP_REPORT_RESP);
					resportResp.setSeqByte(sequenceIdBytes);
					resportResp.setResult((byte)0);
					this.send(session, resportResp.toByteArry());
					
				}else{
					logger.warn("【sgip report 接收 解析失败】序列号,commandId:"+commandId);
				}
				break;
			case SgipCommand.SGIP_SUBMIT:
				SgipMsgSubmitResp submitResp=new SgipMsgSubmitResp();
				submitResp.setTotalLength(20+1+8);
				submitResp.setCommandId(SgipCommand.SGIP_SUBMIT_RESP);
				submitResp.setSeqByte(sequenceIdBytes);
				submitResp.setResult((byte)0);
				submitResp.setSeqStr(SgipCommand.getSeqStr(sequenceIdBytes));
				logger.info("【sgip SGIP_SUBMIT】seqStr:"+submitResp.getSeqStr());
				this.send(session, submitResp.toByteArry());
				break;
			default:
				logger.error("【sgipqd无法解析SMG返回的包结构】包长度为:"+totalLen+",commandId:"+commandId);
				break;
		}
		
	}

	/**
	 * 客户端关闭
	 */
	public void sessionClosed(IoSession session) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		
		logger.info("客户端关闭sessionClosed,clientIP:" + clientIP);
		
	}
	
	/**
	 * 当一个新客户端连接后触发此方法
	 */
	public void sessionCreated(IoSession session) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		logger.info("有新客户端连接sessionCreated,clientIP:" + clientIP);
	}

	/**
	 * 当连接空闲时触发此方法
	 */
	public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		
		logger.info("客户端连接闲置sessionIdle,clientIP:" + clientIP);
		session.closeNow();
	}

	/**
	 * 当一个客户端连接进入时
	 */
	public void sessionOpened(IoSession session) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		logger.info("客户端连接成功sessionOpened,clientIP:" + clientIP);
		
	}

	public SgipQdServer() throws IOException {
//		NioSocketAcceptor acceptor = new NioSocketAcceptor();
		acceptor = new NioSocketAcceptor();
		acceptor.getFilterChain().addLast("codec",
				new ProtocolCodecFilter(new DefaultMinaCodecFactory(new FEncoder(), new FDecoder())));
		acceptor.setHandler(this);
		SocketSessionConfig scfg = acceptor.getSessionConfig();
		scfg.setTcpNoDelay(true);
		scfg.setReadBufferSize(2048);
		scfg.setIdleTime(IdleStatus.BOTH_IDLE, 20);
		scfg.setSoLinger(0); 
		scfg.setWriteTimeout(10);   //调整超时时间
		scfg.setKeepAlive(true);    //是否保持长连接
		if(StringUtils.isNotBlank(socketPort)){
			socketAddres=new InetSocketAddress(Integer.parseInt(socketPort));
			acceptor.bind(socketAddres);
			logger.info("【sgipqd】 mina服务启动完成,port:"+socketPort);
		}else{
			logger.warn("socketPort 未配置");
		}
	}

	synchronized public static SgipQdServer getInstance() {
		if (null == _instance) {
			logger.info("【sgipqd】-------启动mina服务----------");
			try {
				_instance = new SgipQdServer();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return _instance;
	}

	public void send(IoSession session, byte dateBuf[]) {
		try {
			session.write(dateBuf);
		} catch (Exception e) {
			logger.error("发送消息异常" + e.getMessage());
			e.printStackTrace();
		}
	}
	
	public void closeSocketServer() {
		//方法释放资源
		logger.info("【sgipqd】关闭mina服务");
		if (null!=acceptor) {  
            acceptor.unbind(socketAddres);  
            acceptor.getFilterChain().clear();  // 清空Filter chain，防止下次重新启动时出现重名错误  
            acceptor.dispose();                 // 可以另写一个类存储IoAccept，通过spring来创建，这样调用dispose后也会重新创建一个新的。或者可以在init方法内部进行创建。  
            acceptor = null;  
        }  
	}
	public static void main(String[] args) {
		SgipQdServer.getInstance();
	}
}

